#!/bin/sh
#
# This is part of OpenIPC.org project | 2022.01.01
#

# SoC detect
chipid=$(ipcinfo --chip-name)

# MMZ config
mem_start=0x80000000 # phy mem start

mem_total=$(fw_printenv -n totalmem | tr -d 'M')
mem_total=${mem_total:=128}

os_mem_size=$(fw_printenv -n osmem | tr -d 'M')
os_mem_size=${os_mem_size:=32}

report_error() {
        echo "******* Error: There's something wrong, please check! *****"
        exit 1
}

insert_mmz() {
        insmod mmz.ko mmz=anonymous,0,$mmz_start,$mmz_size anony=1 || report_error
}

insert_detect() {
        cd /lib/modules/4.9.37/hisilicon
        insert_mmz
        insmod hi_media.ko
        insmod hi3516a_base.ko
        insmod hi3516a_sys.ko vi_vpss_online=$b_arg_online sensor=unknown mem_total=$mem_total
        insert_isp
        insmod sensor_i2c.ko
        insmod sensor_spi.ko
        SENSOR=ar0230 insert_sns
}

remove_detect() {
        rmmod -w sensor_spi
        rmmod -w sensor_i2c
        rmmod -w hi3516a_isp
        rmmod -w hi3516a_sys
        rmmod -w hi3516a_base
        rmmod -w hi_media
        rmmod -w mmz
        rmmod -w sys_config
}

insert_audio() {
        insmod acodec.ko
        insmod hi3516a_aio.ko
        insmod hi3516a_ai.ko
        insmod hi3516a_ao.ko
        insmod hi3516a_aenc.ko
        insmod hi3516a_adec.ko
        echo "insert audio"
}

remove_audio() {
        rmmod -w hi3516a_adec
        rmmod -w hi3516a_aenc
        rmmod -w hi3516a_ao
        rmmod -w hi3516a_ai
        rmmod -w hi3516a_aio
        rmmod -w acodec
        echo "remove audio"
}

remove_sns() {
        rmmod -w sensor_spi &>/dev/null
        rmmod -w sensor_i2c &>/dev/null
}

sys_config() {
        # pinmux configuration
        devmem 0x200f0000 32 0x1 # 0: GPIO0_5, 1: SENSOR_CLK
        devmem 0x200f0004 32 0x1 # 1: FLASH_TRIG, 0: GPIO0_6, 2: SPI1_CSN1
        devmem 0x200f0008 32 0x1 # 1: SHUTTER_TRIG, 0: GPIO0_7, 2: SPI1_CSN2

        # clock configuration
        devmem 0x20030030 32 0x00004005 # AVC-300M VGS-300M VPSS-250M VEDU-300M mda1axi 250M mda0axi 300M DDR-250
        devmem 0x20030104 32 0x3        # VICAP-198M VPSS-198M
        devmem 0x2003002c 32 0x90007    # VICAP-250M, ISP unreset & clk en, Sensor clk en-37.125M, clk reverse
        #devmem 0x20030034 32 0xffc             # VDP-1080p@60fps unreset & clk en
        #devmem 0x20030034 32 0xef74            # VDP-PAL/NTSC
        devmem 0x20030040 32 0x2002 # VEDU0 AVC unreset & clk en
        devmem 0x20030048 32 0x2    # VPSS0 unreset & clk en

        devmem 0x20030058 32 0x2 # TDE unreset & clk en
        devmem 0x2003005c 32 0x2 # VGS unreset & clk en
        devmem 0x20030060 32 0x2 # JPGE  unreset & clk en

        devmem 0x20030068 32 0x2 # MDU unreset & clk en
        devmem 0x2003006c 32 0x2 # IVE-300MHz unreset & clk en
        #devmem 0x20030070 32 0x2       # VOIE unreset & clk en

        devmem 0x2003007c 32 0x2 # cipher unreset & clk en
        devmem 0x2003008c 32 0xe # aio MCLK PLL 1188M, unreset & clk en
        #devmem 0x200300d8 32 0xa;      # ddrt

        # system configuration
        devmem 0x201200E0 32 0xd # internal codec:AIO MCLK out, CODEC AIO TX MCLK

        if [ $b_arg_online -eq 1 ]; then
                # -------------vi vpss online
                devmem 0x20120004 32 0x40000000 # online, SPI1 CS0

                #pri config
                devmem 0x20120058 32 0x26666400 # each module 4bit:vedu       ddrt_md  ive  aio    jpge    tde   vicap  vdp
                devmem 0x2012005c 32 0x66666103 # each module 4bit:sfc_nand   sfc_nor  nfc  sdio1  sdio0   a7    vpss   vgs
                devmem 0x20120060 32 0x66266666 # each module 4bit:reserve    reserve  avc  usb    cipher  dma2  dma1   gsf

                #timeout config
                devmem 0x20120064 32 0x00000011 # each module 4bit:vedu       ddrt_md  ive  aio    jpge    tde   vicap  vdp
                devmem 0x20120068 32 0x00000020 # each module 4bit:sfc_nand   sfc_nor  nfc  sdio1  sdio0   a7    vpss   vgs
                devmem 0x2012006c 32 0x00000000 # each module 4bit:reserve    reserve  avc  usb    cipher  dma2  dma1   gsf
        else
                devmem 0x20120004 32 0x0 # offline, mipi SPI1 CS0;
                # pri config
                devmem 0x20120058 32 0x26666401 # each module 4bit:vedu       ddrt_md  ive  aio    jpge    tde   vicap  vdp
                devmem 0x2012005c 32 0x66666112 # each module 4bit:sfc_nand   sfc_nor  nfc  sdio1  sdio0   a7    vpss   vgs
                devmem 0x20120060 32 0x66266666 # each module 4bit:reserve    reserve  avc  usb    cipher  dma2  dma1   gsf
                # timeout config
                devmem 0x20120064 32 0x00000011 # each module 4bit:vedu       ddrt_md  ive  aio    jpge    tde   vicap  vdp
                devmem 0x20120068 32 0x00000000 # each module 4bit:sfc_nand   sfc_nor  nfc  sdio1  sdio0   a7    vpss   vgs
                devmem 0x2012006c 32 0x00000000 # each module 4bit:reserve    reserve  avc  usb    cipher  dma2  dma1   gsf
        fi
}

insert_isp() {
        case $SENSOR in
        *)
                insmod hi3516a_isp.ko
                ;;
        esac
}

insert_sns() {
        case $SENSOR in
        ar0130 | 9m034)
                devmem 0x200f0050 32 0x2 # i2c0_scl
                devmem 0x200f0054 32 0x2 # i2c0_sda
                ;;
        mt9p006)
                devmem 0x200f0050 32 0x2 # i2c0_scl
                devmem 0x200f0054 32 0x2 # i2c0_sda

                devmem 0x2003002c 32 0xE0007 # sensor unreset, clk 24MHz, VI 250MHz
                ;;
        imx136)
                devmem 0x200f0050 32 0x1 # spi0_sclk
                devmem 0x200f0054 32 0x1 # spi0_sdo
                devmem 0x200f0058 32 0x1 # spi0_sdi
                devmem 0x200f005c 32 0x1 # spi0_csn
                ;;
        imx123)
                devmem 0x200f0050 32 0x1 # spi0_sclk
                devmem 0x200f0054 32 0x1 # spi0_sdo
                devmem 0x200f0058 32 0x1 # spi0_sdi
                devmem 0x200f005c 32 0x1 # spi0_csn

                #devmem 0x2003002c 32 0xb0007            # sensor unreset, clk 27MHz, VI 250MHz
                devmem 0x2003002c 32 0x90007 # sensor unreset, clk 37.125MHz, VI 250MHz
                devmem 0x20030104 32 0x0     # VI 250MHz
                insmod sensor_spi.ko
                ;;
        imx178)
                devmem 0x200f0050 32 0x2     # i2c0_scl
                devmem 0x200f0054 32 0x2     # i2c0_sda
                devmem 0x2003002c 32 0xF0007 # sensor unreset, clk 25MHz, VI 250MHz
                #devmem 0x2003002c 32 0x90007            # sensor unreset, clk 37.125MHz, VI 250MHz
                ;;
        imx185)
                devmem 0x200f0050 32 0x1 # spi0_sclk
                devmem 0x200f0054 32 0x1 # spi0_sdo
                devmem 0x200f0058 32 0x1 # spi0_sdi
                devmem 0x200f005c 32 0x1 # spi0_csn

                devmem 0x2003002c 32 0x90007 # sensor unreset, clk 37.125MHz, VI 250MHz

                insmod sensor_spi.ko
                ;;
        imx291)
                devmem 0x200f0050 32 0x2 # i2c0_scl
                devmem 0x200f0054 32 0x2 # i2c0_sda

                devmem 0x2003002c 32 0x90005 # sensor unreset, clk 37.125MHz, VI 148MHz
                ;;

        imx117)
                devmem 0x200f0050 32 0x1 # spi0_sclk
                devmem 0x200f0054 32 0x1 # spi0_sdo
                devmem 0x200f0058 32 0x1 # spi0_sdi
                devmem 0x200f005c 32 0x1 # spi0_csn

                devmem 0x200f00dc 32 0x1
                devmem 0x200f00e0 32 0x1
                devmem 0x20030038 32 0x6

                devmem 0x20131020 32 0x30de8
                devmem 0x20131024 32 0x30de5
                devmem 0x2013102c 32 0x5

                devmem 0x20131060 32 0xbf
                devmem 0x20131064 32 0xbc
                devmem 0x2013106c 32 0x5

                devmem 0x2003002c 32 0x90007 # sensor unreset, clk 37.125MHz, VI 250MHz

                insmod sensor_spi.ko sensor=imx117
                ;;
        mn34220)
                devmem 0x200f0050 32 0x2 # i2c0_scl
                devmem 0x200f0054 32 0x2 # i2c0_sda

                devmem 0x2003002c 32 0x90007 # sensor unreset, clk 37.125MHz, VI 250MHz
                ;;
        ov5658)
                devmem 0x200f0050 32 0x2     # i2c0_scl
                devmem 0x200f0054 32 0x2     # i2c0_sda
                devmem 0x2003002c 32 0xE0007 # sensor unreset, clk 24MHz, VI 250MHz
                devmem 0x20030104 32 0x0     # VI 250MHz
                ;;
        ov4689)
                devmem 0x200f0050 32 0x2     # i2c0_scl
                devmem 0x200f0054 32 0x2     # i2c0_sda
                devmem 0x2003002c 32 0xE0007 # sensor unreset, clk 24MHz, VI 250MHz
                devmem 0x20030104 32 0x0
                ;;
        ar0230 | ar0237 | sc4236)
                devmem 0x200f0050 32 0x2 # i2c0_scl
                devmem 0x200f0054 32 0x2 # i2c0_sda

                devmem 0x2003002c 32 0xB0007 # sensor unreset, clk 27MHz, VI 250MHz
                ;;
        ar0330 | ar0330_i2c_dc)
                devmem 0x200f0050 32 0x2 # i2c0_scl
                devmem 0x200f0054 32 0x2 # i2c0_sda

                devmem 0x2003002c 32 0xE0007 # sensor unreset, clk 24MHz, VI 250MHz
                ;;
        os05a)
                devmem 0x200f0050 32 0x2     # i2c0_scl
                devmem 0x200f0054 32 0x2     # i2c0_sda
                devmem 0x2003002c 32 0xE0003 # sensor unreset, clk 24MHz, VI 297MHz
                devmem 0x20030104 32 0x0     # Sensor 24M
                ;;
        *)
                echo "xxxx Invalid sensor type $SNS_TYPE xxxx"
                report_error
                ;;
        esac

}
insert_ko() {
        sys_config

        insert_mmz

        insmod hi_media.ko
        insmod hi3516a_base.ko

        insmod hi3516a_sys.ko vi_vpss_online=$b_arg_online sensor=$SENSOR mem_total=$mem_total || report_error

        insmod hi3516a_tde.ko
        insmod hi3516a_region.ko
        insmod hi3516a_vgs.ko

        insert_isp

        insmod hi3516a_viu.ko detect_err_frame=10
        insmod hi3516a_vpss.ko rfr_frame_comp=1
        insmod hi3516a_vou.ko
        #insmod hi3516a_vou.ko transparentTransmit=1 #enable transparentTransmit
        #insmod hifb.ko video="hifb:vram0_size:1620"     # default pal

        insmod hi3516a_rc.ko
        insmod hi3516a_venc.ko
        insmod hi3516a_chnl.ko #ChnlLowPower=1
        insmod hi3516a_h264e.ko H264eMiniBufMode=1
        insmod hi3516a_h265e.ko H265eMiniBufMode=1
        insmod hi3516a_jpege.ko
        #insmod hi3516a_ive.ko save_power=0
        #insmod hi3516a_ive.ko

        insmod sensor_i2c.ko
        insmod pwm.ko
        #insmod piris.ko

        insert_sns
        insert_audio

        insmod hi_mipi.ko
        insmod wdt.ko #nodeamon=1
        echo "==== Your input Sensor type is $SENSOR ===="
}

remove_ko() {
        rmmod -w wdt
        remove_audio
        remove_sns

        rmmod -w pwm
        #rmmod -w piris
        #rmmod -w hi3516a_ive

        rmmod -w hi3516a_rc
        rmmod -w hi3516a_jpege
        rmmod -w hi3516a_h265e
        rmmod -w hi3516a_h264e
        rmmod -w hi3516a_chnl
        rmmod -w hi3516a_venc

        #rmmod -w hifb
        rmmod -w hi3516a_vou
        rmmod -w hi3516a_vpss
        rmmod -w hi3516a_viu
        rmmod -w hi_mipi

        rmmod -w hi3516a_vgs
        rmmod -w hi3516a_region
        rmmod -w hi3516a_tde

        rmmod -w hi3516a_isp
        rmmod -w hi3516a_sys
        rmmod -w hi3516a_base
        rmmod -w hi_media
        rmmod -w mmz
}

load_usage()
{
	echo "Usage:  ./load_hisilicon [-option] [sensor_name]"
	echo "options:"
	echo "    -i                       insert modules"
	echo "    -r                       remove modules"
	echo "    -a                       remove modules first, then insert modules"
	echo "    -sensor sensor_name      config sensor type [default: imx307]"
	echo "    -h                       help information"
	echo -e "for example: ./load_hisilicon -i -sensor imx307 -osmem 32M -board demo -yuv0 0\n"
}

calc_mmz_info() {
        mmz_start=$(echo "$mem_start $os_mem_size" |
                awk 'BEGIN { temp = 0; }
        {
                temp = $1/1024/1024 + $2;
        }
    END { printf("0x%x00000\n", temp); }')

        mmz_size=$(echo "$mem_total $os_mem_size" |
                awk 'BEGIN { temp = 0; }
        {
                temp = $1 - $2;
        }
    END { printf("%dM\n", temp); }')
        echo "mmz_start: $mmz_start, mmz_size: $mmz_size"
}

######################parse arg###################################
b_arg_os_mem=0
b_arg_total_mem=0
b_arg_sensor=0
b_arg_insmod=0
b_arg_remove=0
b_arg_online=1

for arg in $@; do
        if [ $b_arg_total_mem -eq 1 ]; then
                b_arg_total_mem=0
                mem_total=$arg

                if [ -z $mem_total ]; then
                        echo "[error] mem_total is null"
                        exit
                fi
        fi

        if [ $b_arg_os_mem -eq 1 ]; then
                b_arg_os_mem=0
                os_mem_size=$arg

                if [ -z $os_mem_size ]; then
                        echo "[error] os_mem_size is null"
                        exit
                fi
        fi

        if [ $b_arg_sensor -eq 1 ]; then
                b_arg_sensor=0
                SENSOR=$arg
        fi

        case $arg in
        "-i")
                b_arg_insmod=1
                ;;
        "-r")
                b_arg_remove=1
                ;;
        "-a")
                b_arg_insmod=1
                b_arg_remove=1
                ;;
        "-h")
                load_usage
                ;;
        "-sensor")
                b_arg_sensor=1
                ;;
        "-osmem")
                b_arg_os_mem=1
                ;;
        "-total")
                b_arg_total_mem=1
                ;;
        "-offline")
                b_arg_online=0
                ;;
        esac
done
#######################parse arg end########################

if [ $os_mem_size -ge $mem_total ]; then
        echo "[err] os_mem[$os_mem_size], over total_mem[$mem_total]"
        exit
fi

calc_mmz_info

#######################Action###############################

if [ $# -lt 1 ]; then
        load_usage
        exit 0
fi

# Sensor config
# SENSOR=${SENSOR:=imx307}
#

if [ -n "$SENSOR" ]; then
        logger -s -p daemon.info -t hisilicon "Manualy set SENSOR as ${SENSOR}"
else
        if fw_printenv -n sensor >/dev/null; then
                SENSOR_ENV=$(fw_printenv -n sensor)
                export SENSOR=${SENSOR_ENV}
                logger -s -p daemon.info -t hisilicon "Get data from environment and set SENSOR as ${SENSOR}"
        else
                insert_detect
                SENSOR_DETECT=$(ipcinfo --short-sensor)
                export SENSOR=${SENSOR_DETECT:=unknown}
                remove_detect
                logger -s -p daemon.info -t hisilicon "Get data from ipcinfo and set SENSOR as ${SENSOR}"
                fw_setenv sensor $SENSOR && logger -s -p daemon.info -t hisilicon "Write detected ${SENSOR} to U-Boot ENV"
        fi
fi

if [ $b_arg_remove -eq 1 ]; then
        remove_ko
fi

if [ "$SENSOR" = "unknown" ]; then
        exit 1
else
        if [ $b_arg_insmod -eq 1 ]; then
                cd /lib/modules/4.9.37/hisilicon
                insert_ko
        fi
fi
